package falcon.script;

import java.util.ArrayList;
import java.util.HashMap;

import falcon.common.Errno;
import falcon.common.TextFile;

public final class FalconLangLoader {
	
	public static final class ProcLine {
		public String line;
		public int offset;
		public int count;
	}
	
	public static final class ProcInstruction {
		public FalconLangInstruction instruction;
		public int row;
	}
	
	public static final class Procedure {
		public int errno;
		public long version;
		public String name;
		public String path;
		public ProcLine[] lines;
		public ProcInstruction[] list;
	}

	public FalconLangLoader(FalconLangGlobal global) {
		m_global = global;
		m_map = new HashMap<String, FalconLangLoader.Procedure>();
	}
	
	public Procedure load(String path) {
		long version = TextFile.getLastMtime(path);
		Procedure procedure = m_map.get(path);
		if (procedure != null && procedure.errno == Errno.SUCCESS && version == procedure.version) {
			return procedure;
		}
		procedure = new Procedure();
		procedure.version = version;
		procedure.name = "";
		procedure.path = path;
		try {
			procedure.errno = doLoad(procedure);
		} finally {
			m_map.put(path, procedure);
		}
		return procedure;
	}
	
	private int doLoad(Procedure procedure) {
		String[] lines = TextFile.readLines(procedure.path);
		if (lines == null) {
			return Errno._NO_SUCH_FILE_OR_DIRECTORY;
		}
		procedure.lines = new ProcLine[lines.length];

		FalconLangCompiler compiler = m_global.getCompiler();
		compiler.prepare();
		int errno;
		ArrayList<ProcInstruction> pInstructions = new ArrayList<FalconLangLoader.ProcInstruction>(256);
		for (int x = 0; x < lines.length; x ++) {
			String line = lines[x];
			if ("".equals(line)) {
				continue;
			}
			errno = compiler.analyze(line);
			if (errno != Errno.SUCCESS) {
				return errno;
			}
			errno = compiler.translate();
			if (errno != Errno.SUCCESS) {
				return errno;
			}
			ProcLine pLine = new ProcLine();
			pLine.line = line;
			pLine.offset = pInstructions.size();
			FalconLangInstruction[] list = compiler.getInstruction();
			for (int y = 0; y < list.length; y ++) {
				FalconLangInstruction instruction = list[y];
				ProcInstruction pInstruction = new ProcInstruction();
				pInstruction.instruction = instruction;
				pInstruction.row = x;
				pInstructions.add(pInstruction);
			}
			pLine.count = list.length;
			procedure.lines[x] = pLine;
		}
		procedure.list = new ProcInstruction[pInstructions.size()];
		pInstructions.toArray(procedure.list);
		return Errno.SUCCESS;
	}
	
	private FalconLangGlobal m_global;
	private HashMap<String, Procedure> m_map;
}
